﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.Routing;

namespace CID.Web.Support
{
    //TODO: the html elements being generated are not getting the appropriate class attribute, need to review how is done by the EditorFor() and implement something similar
    public static class KnockoutExtensions
    {
        private static IDictionary<string, object> DecorateHtmlAttributesWithDataBind<TModel, TValue>(this Expression<Func<TModel, TValue>> expression, IDictionary<string, object> dictionary = null, string bindingName = "value")
        {
            const string DataBindAttribute = "data-bind";

            if (dictionary == null) dictionary = new Dictionary<string, object>();
            if (!dictionary.ContainsKey(DataBindAttribute)) dictionary.Add(DataBindAttribute, String.Empty);
            
            var dataBind = dictionary[DataBindAttribute].ToString();
            dataBind = dataBind + (String.IsNullOrEmpty(dataBind)? "" : ", ") + String.Format("{0}: {1}", bindingName, (expression.Body as MemberExpression).Member.Name);
            dictionary[DataBindAttribute] = dataBind;
            
            return dictionary;
        }

        public static MvcHtmlString KOTextBoxFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
        {
            return html.TextBoxFor(expression, expression.DecorateHtmlAttributesWithDataBind(new RouteValueDictionary().DecorateWithClass(Styling.TextBoxClass)));
        }

        public static MvcHtmlString KOTextAreaFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, object htmlAttributes = null)
        {
            return html.TextAreaFor(expression, expression.DecorateHtmlAttributesWithDataBind(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes).DecorateWithClass(Styling.TextBoxClass, Styling.MultiLineClass)));
        }

        public static MvcHtmlString KOHiddenFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
        {
            return html.HiddenFor(expression, expression.DecorateHtmlAttributesWithDataBind());
        }

        public static MvcHtmlString KOCheckBoxFor<TModel>(this HtmlHelper<TModel> html, Expression<Func<TModel, bool>> expression)
        {
            return html.CheckBoxFor(expression, expression.DecorateHtmlAttributesWithDataBind(bindingName:"checked"));
        }

        public static MvcHtmlString KODropDownListForEnum<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, Type enumType, object selectedValue, object htmlAttributes)
        {
            return htmlHelper.KODropDownListForEnum(expression, enumType, selectedValue, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
        }

        public static MvcHtmlString KODropDownListForEnum<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, Type enumType, object selectedValue = null, IDictionary<string, object> htmlAttributes = null)
        {
            return htmlHelper.DropDownListForEnum(expression, enumType, selectedValue, expression.DecorateHtmlAttributesWithDataBind(htmlAttributes));
        }

        public static MvcHtmlString KODropDownListForEntity<TModel, TProperty, TReferencedEntityViewModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<TReferencedEntityViewModel> values, int? selectedId, object htmlAttributes)
            where TReferencedEntityViewModel : Models.INamedViewModel
        {
            return htmlHelper.KODropDownListForEntity(expression, values, selectedId, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
        }

        public static MvcHtmlString KODropDownListForEntity<TModel, TProperty, TReferencedEntityViewModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, Expression<Func<TModel, String>> expressionText, IEnumerable<TReferencedEntityViewModel> values, int? selectedId, IDictionary<string, object> htmlAttributes = null)
            where TReferencedEntityViewModel : Models.INamedViewModel
        {
            return htmlHelper.KODropDownListForEntity(expression, values, selectedId, expressionText.DecorateHtmlAttributesWithDataBind(htmlAttributes, "valueText"));
        }

        public static MvcHtmlString KODropDownListForEntity<TModel, TProperty, TReferencedEntityViewModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<TReferencedEntityViewModel> values, int? selectedId, IDictionary<string, object> htmlAttributes = null)
            where TReferencedEntityViewModel : Models.INamedViewModel
        {
            return htmlHelper.DropDownListForEntity(expression, values, selectedId, expression.DecorateHtmlAttributesWithDataBind(htmlAttributes));
        }

        /// <summary>
        /// Writes an opening &lt;form&gt; tag that can be used for editing children entities in conjunction with KnockoutJS templates.
        /// </summary>
        /// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
        /// <param name="id">The id for the &lt;form&gt; element</param>
        /// <returns>An opening &lt;form&gt; tag.</returns>
        /// <remarks>The form will be non submittable as the onsubmit event will be preventing the submission</remarks>
        public static MvcForm KOBeginFormChildEditor(this HtmlHelper htmlHelper, string id)
        {
            return htmlHelper.BeginForm("", "", FormMethod.Post, new { id = id, onsubmit="javascript: return false;" });
        }

        public static MvcHtmlString KOPartialChildEditor<TModel, TChild>(this HtmlHelper<TModel> htmlHelper, string partialViewName, string htmlFieldPrefix, TChild child)
        {
            var childHtmlHelper = new HtmlHelper<TChild>(htmlHelper.ViewContext, new ViewDataContainer<TChild>());
            childHtmlHelper.ViewData.TemplateInfo.HtmlFieldPrefix = htmlFieldPrefix;

            return childHtmlHelper.Partial(partialViewName, child);
        }
    }
}